iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Mobile Development

從零開始的8-bit迷宮探險!Swift SpriteKit 遊戲開發實戰系列 第 26

從零開始的8-bit迷宮探險【Level 26】這遊戲沒有華佗,不能補血啊!Game Over 場景切換

  • 分享至 

  • xImage
  •  

一直遭到攻擊的山姆,生命值也快用盡了。
「快離開我們的地盤!」山姆被 Rain 跟 Storm 團團包圍著。
「這迷宮的出口,不知道長什麼樣子呢?」

今日目標

  • 切換至遊戲結束場景
  • 顯示本次遊戲得分及歷史最高得分
  • 加上破紀錄提示
  • 加上重新開始按鈕,可以切換至遊戲場景並重新開始遊戲

PS. 這裡是開發 iOS 手機遊戲的系列文,如果還沒看過之前 劇情 文章的朋友,歡迎先點這邊回顧唷!


建立遊戲結束場景

首先,我們先新增新的場景,包含 .sks 及 .swift,並且將對應的類別名稱填入 .sks 檔案中

新增遊戲結束場景

  • 點選新增檔案
    https://imgur.com/DyRgPfA.png

  • 選擇 SpriteKit Scene -> Next
    https://imgur.com/quZHr3g.png

  • 將檔案命名為 GameOverScene,點擊 Create 按鈕,完成 .sks 檔的新增

新增遊戲結束類別

  • 點選新增檔案
    https://imgur.com/DyRgPfA.png

  • 選擇 Swift File -> Next
    https://imgur.com/IJukGWI.png

  • 將檔案命名為 GameOverScene,點擊 Create 按鈕,完成 .swift 檔的新增

  • 將 GameOverScene.sks 的 Custom Class 填上 GameOverScene
    https://imgur.com/NnG0FAl.png

遊戲結束類別內容

  • 引入 SpriteKit
  • 新增兩個分數變數 scorebestScore,用來記錄遊戲得分及最高得分
  • 新增重新開始按鈕,包含背景圖片及文字,使用 SKSpriteNode 及 SKLabelNode 組合而成
  • 設定背景顏色為 .black
  • 加上遊戲結束的標題 labelTitle,顯示 Game Over!
  • 加上遊戲得分及最高得分的文字節點 labelScorelabelBest
  • 加上重新開始按鈕 restartNodelabelRestart
  • GameOverScene.swift
import SpriteKit

class GameOverScene: SKScene {
    var score: Int = 0
    var bestScore: Int = 0
    var restartNode = SKSpriteNode(imageNamed: "button")
    var labelRestart = SKLabelNode(text: "RESTART")
    
    override func didMove(to view: SKView) {
        self.backgroundColor = .black
        
        let labelTitle = SKLabelNode(text: "Game Over!")
        labelTitle.fontColor = UIColor(red: 39/255, green: 90/255, blue: 129/255, alpha: 1)
        labelTitle.fontSize = CGFloat(50)
        labelTitle.fontName = "Copperplate"
        labelTitle.position = CGPoint(x: 0, y: 200)
        labelTitle.horizontalAlignmentMode = .center
        labelTitle.verticalAlignmentMode = .center
        self.addChild(labelTitle)
        
        let labelScore = SKLabelNode(text: "Your Score: \(self.score)")
        labelScore.fontColor = UIColor.white
        labelScore.fontSize = CGFloat(24)
        labelScore.fontName = "Copperplate"
        labelScore.position = CGPoint(x: 0, y: 100)
        labelScore.horizontalAlignmentMode = .center
        labelScore.verticalAlignmentMode = .center
        self.addChild(labelScore)
        
        let labelBest = SKLabelNode(text: "Best Score: \(self.bestScore)")
        labelBest.fontColor = UIColor.white
        labelBest.fontSize = CGFloat(24)
        labelBest.fontName = "Copperplate"
        labelBest.position = CGPoint(x: 0, y: 60)
        labelBest.horizontalAlignmentMode = .center
        labelBest.verticalAlignmentMode = .center
        self.addChild(labelBest)
        
        self.restartNode.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        self.restartNode.size.width = CGFloat(208)
        self.restartNode.size.height = CGFloat(74)
        self.restartNode.position = CGPoint(x: 0, y: -100)
        self.addChild(self.restartNode)
        
        self.labelRestart.fontColor = UIColor(red: 39/255, green: 90/255, blue: 129/255, alpha: 1)
        self.labelRestart.fontSize = CGFloat(30)
        self.labelRestart.fontName = "Copperplate"
        self.labelRestart.position = CGPoint(x: 0, y: 2)
        self.labelRestart.verticalAlignmentMode = .center
        self.restartNode.addChild(self.labelRestart)
    }
}

切換至場景

  • 調整 gameStop 方法
    • 將儲存最高分的程式碼移動到 gameOver()
    • 在生命值小於 0 時,啟動一個 Timer,3 秒後執行 gameOver()
  • gameOver
    • 遊戲結束時,將最高分儲存到本機中
    • 新增一個 GameOverScene 實體,將 self.scoreself.bestScore 的值寫入
    • 使用 SKTransition,讓遊戲場景與遊戲結束場景中間有個轉場動畫特效。特效的選擇有很多,大家可以帶入自己喜歡的特效,這邊使用 SKTransition.doorway
    • 帶入特效並切換至 GameOverScene 場景
  • GameScene.swift
class GameScene: SKScene {
    ...
    func gameStop() {
        ...
//        let setting = Setting(bestScore: self.bestScore)
//        self.setBestScore(setting: setting)

        self.samLife -= 1
        if self.samLife < 0 {
            // 遊戲結束場景
            Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(gameOver), userInfo: nil, repeats: false)
        } else {
            // 重新開始
            Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(gameReset), userInfo: nil, repeats: false)
        }
    }
    @objc func gameOver() {
        // 儲存最高分
        let setting = Setting(bestScore: self.bestScore)
        self.setBestScore(setting: setting)
        
        // 切換場景
        if let endScene = GameOverScene(fileNamed: "GameOverScene") {
            endScene.score = self.score
            endScene.bestScore = self.bestScore
            let transition = SKTransition.doorway(withDuration: 1)
            self.view?.presentScene(endScene, transition: transition)
        }
    }
}

執行結果

成功切換至遊戲結束場景囉!而且也顯示了得分紀錄
https://imgur.com/adCI27n.gif


破紀錄文字

我們再加上破紀錄的提示文字,讓場景更豐富。判斷當本次遊戲得分大於或等於最高得分,且不為 0 時,就顯示破紀錄文字。這邊使用之前用過的 SKAction.fadeAlpha 來製作讓文字閃爍的感覺

  • GameOverScene.swift
class GameOverScene: SKScene {
    override func didMove(to view: SKView) {
        ...
        if self.score >= self.bestScore && self.score != 0 {
            let labelBreak = SKLabelNode(text: "Break the record!!")
            labelBreak.fontColor = UIColor.white
            labelBreak.fontSize = CGFloat(32)
            labelBreak.position = CGPoint(x: 0, y: 0)
            let ani1 = SKAction.fadeAlpha(to: 0, duration: 0.6)
            let ani2 = SKAction.fadeAlpha(to: 1, duration: 0.3)
            let aniAlpha = SKAction.sequence([ani1, ani2])
            let aniRepeat = SKAction.repeatForever(aniAlpha)
            labelBreak.run(aniRepeat)
            self.addChild(labelBreak)
        }
    }
}

執行結果

畫面中出現閃亮亮的破紀錄了!/images/emoticon/emoticon74.gif
https://imgur.com/yLsROFv.gif


重新開始

最後,讓重新開始按鈕,可以被點擊吧!
跟之前用過的方式一樣,覆寫 touchesBegan 方法,判斷當觸碰的位置是 self.restartNodeself.labelRestart 時,切換回去 GameScene 場景,並且加上 SKTransition.fade 的轉場效果,最後呼叫 applySafeArea 方法,校正畫面。

  • GameOverScene.swift
class GameOverScene: SKScene {
    ...
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in (touches) {
            let location = touch.location(in: self)
            if self.atPoint(location) == self.restartNode || self.atPoint(location) == self.labelRestart {
                if let gameScene = GameScene(fileNamed: "GameScene") {
                    let transition = SKTransition.fade(withDuration: 1)
                    self.view?.presentScene(gameScene, transition: transition)
                    gameScene.applySafeArea()
                }
            }
        }
    }
}

執行結果

按下重新開始遊戲按鈕後,回到遊戲場景,可以看到生命值重新回到 3,右上角也有之前的最高得分
https://imgur.com/hjcFHht.gif


參考來源:
SKTransition
fadeAlpha(to:duration:)


上一篇
從零開始的8-bit迷宮探險【Level 25】今天又是嶄新的一天,回到原點
下一篇
從零開始的8-bit迷宮探險【Level 27】神助攻-老弟幫我配個音效
系列文
從零開始的8-bit迷宮探險!Swift SpriteKit 遊戲開發實戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言